package com.project.shiro;

import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.project.myBeans.ConfigParameters;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.shiro.web.filter.authc.AuthenticationFilter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created by TAO on 2016/3/25.
 *
 * shiro 自定义拦截器/过滤器
 */
public class AccessTokenFilter extends AuthenticationFilter  {

    @Autowired
    private ConfigParameters configParameters; //这里使用@Autowired无法注入成功,后面代码有解决方法

    private static final String TOKEN = "token";

    private Jws jws;

    //@Value("${config.jwtSecret}")
    private String jwtSecret="f4e2e52034348f86aefgde581c0f9eb5";

    protected Logger log = LogManager.getLogger(getClass());

    /**
     * 前后端分离时
     * 约定：在请求API时，在RequestHeaders上都要附加上token

     * 拦截器配置为anon的URI，不会执行onAccessDenied（）方法；
     * 其它URI，则会执行onAccessDenied（）方法；
     */
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {

        return false; //返回false，才会执行onAccessDenied（）方法；
//        return true;  //app测试阶段，返回true
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) {

        log.info("用户进入token校验...");

        HttpServletRequest req = (HttpServletRequest) request;

        String token = req.getHeader(TOKEN);

        //=== 列出所有headers
//        Enumeration headerNames = ((HttpServletRequest) request).getHeaderNames();
//        while (headerNames.hasMoreElements()) {
//            String key = (String) headerNames.nextElement();
//            String value = ((HttpServletRequest) request).getHeader(key);
//            System.out.println(key+"=="+value);
//        }
        //===

        log.info("filter token>>>>>>" + token);

        if (isAccess(token,req)) {
            return onAccessSuccess(req, (HttpServletResponse) response);
        }

        return onAccessFail(req, (HttpServletResponse) response);
    }

    /**
     * 判断token的合法性
     *
     * @param token
     * @return
     */
    @Bean
    public boolean isAccess(String token,HttpServletRequest req) {

        if (StringUtils.isEmpty(token))
            return false;

        if (configParameters == null) {//解决bean无法注入问题
            BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());
            configParameters = (ConfigParameters) factory.getBean("configParameters");
        }

        //验证token
        String key =configParameters.getJwtSecret();

        try {

            jws = Jwts.parser().setSigningKey(key).parseClaimsJws(token); //验证token

            //OK, we can trust this JWT
//            System.out.println("ok1:" + jws.getBody()); //{sub=Joe, iss=userId, exp=1458906942}
//            System.out.println("ok2:" + jsonObject.get("iss"));

            //可进一步判断token与userId(iss)的匹配性

        } catch (Exception e) {
            //don't trust the JWT! 发生异常，则token验证不成功
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 认证成功进行的操作处理
     *
     * @param request
     * @param response
     * @return true 继续后续处理，false 不需要后续处理
     */
    public boolean onAccessSuccess(HttpServletRequest request, HttpServletResponse response) {
        /**
         * refresh_token：利用token超时时间，计算一下剩余时间，剩余时间小于1分钟
         * 开始核发新的token，客户端自动使用新的token，等退出时，就不核发新的token。
         */
//        String key = configParameters.getJwtSecret();
//        Long expirationTime = System.currentTimeMillis() + configParameters.getJwtExpire() * 1000;
//        DateTime dt = new DateTime();
//
//        boolean refreshToken=false; //是否刷新token
//
//        if(refreshToken) {
//            JSONObject jsonObject = JSONObject.parseObject(jws.getBody().toString());
//            Long exp = Long.valueOf(jsonObject.get("exp").toString()) * 1000; //token过期时间，转成毫秒
//
//            if ((exp - System.currentTimeMillis()) < 60 * 1000) { //核发新的token
//                String token = Jwts.builder()         //创建token
//                        .setIssuer(jsonObject.get("iss").toString())
//                        .setExpiration(dt.plusSeconds(configParameters.getJwtExpire()).toDate())
//                        .signWith(SignatureAlgorithm.HS512, key)
//                        .compact();
//                response.setHeader("refresh_token", token); //app端获取token，判断token不为空，则登录成功，否则 登录失败
//                response.setHeader("expires", expirationTime.toString());
//                response.setHeader("isRefreshToken", "true"); //核发新的token
//                System.out.println("refresh_token>>>>>>>>" + token);
//            }
//
//            response.setHeader("isTokenValidity", "true"); //token有效
//        }

        return true;
    }

    /**
     * 认证失败时处理结果
     *
     * @param request
     * @param response
     * @return true 继续后续处理，false 不需要后续处理
     */
    public boolean onAccessFail(HttpServletRequest request, HttpServletResponse response) {

        JSONObject result = new JSONObject();
        try {
            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=utf-8");

            response.setHeader("isTokenValidity", "false"); //token无效或过期
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); //status: 401

            result.put("code", HttpServletResponse.SC_UNAUTHORIZED);
            result.put("msg", "token无效或已过期,请重新登录");
            response.getWriter().write(result.toString()); //输出response到客户端
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

}
